<?php
declare(strict_types=1);

namespace App\Interface\Pay;

use App\Constants\ErrorCode;
use App\Interface\PaymentStrategyInterface;
use App\Job\CheckPaid;
use App\Model\BalanceOrder;
use App\Model\Normal;
use App\Model\Order;
use App\Model\RefundLog;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\Context\ApplicationContext;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\Str;
use Util\Common;
use Hyperf\Di\Annotation\Inject;
use Yansongda\Pay\Pay;
use Hyperf\Logger\LoggerFactory;
use Psr\Log\LoggerInterface;


class AliPaymentStrategy implements PaymentStrategyInterface
{
    protected array $config;
    protected RequestInterface $request;
    private $logger;

    public function __construct()
    {
        $this->config = config('pay');
        $log_name = 'alipay' . date('Y-m-d', time());
        $loggerFactory = container()->get(\Hyperf\Logger\LoggerFactory::class);
        $this->logger = $loggerFactory->get($log_name, 'alipay');
    }

    /**支付通用
     * @param array $params
     * @return array
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function pay(array $params): array
    {
        $class = Str::studly($params['type_mode']);
        return $this->$class($params);
    }

    public function __call($name, $arguments)
    {
        // 处理不存在的实例方法调用
        return '';
    }

    /**支付宝回调
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \Yansongda\Pay\Exception\ContainerException
     * @throws \Yansongda\Pay\Exception\InvalidParamsException
     */
    public function notify($request)
    {
        $pay = Pay::alipay($this->config);
        $data = $pay->callback($request);
        $this->logger->info('支付宝付款成功回调'.json_encode($data));
        if ($data['trade_status'] == 'TRADE_SUCCESS') {
            $params['pay_time'] = date('Y-m-d H:i:s',time());
            $params['out_ord_id'] = $data['trade_no'];
            $order = Order::where('number',$data['out_trade_no'])->first();
            $order->payMent($params);
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('check-paid');
            $driver->push(new CheckPaid($order->number), 30);
            return Pay::alipay($this->config)->success();
        }
        return false;
    }


    public function balance_notify($request){
        $pay = Pay::alipay($this->config);
        $data = $pay->callback($request);
        $this->logger->info('支付宝充值余额回调'.json_encode($data));
        if ($data['trade_status'] == 'TRADE_SUCCESS') {
            $order = BalanceOrder::where('number',$data['out_trade_no'])->first();
            $order->out_ord_id = $data['trade_no'];
            $order->balanceNotify();
            return Pay::alipay($this->config)->success();
        }
        return false;
    }


    public function refund($params){
        $data = Pay::alipay($this->config)->refund([
            'out_trade_no' => $params['number'],
            'refund_amount' => $params['return_fee'],
            '_action' => 'mini',
            'out_request_no'=>$params['refund_no']
        ]);
        if($data['code'] == 10000){
            $refund = RefundLog::where('refund_no',$params['refund_no'])
                ->first();
            $refund->status = 1;
            $refund->refund_time= date('Y-m-d H:i:s');
            $refund->save();
            $order = Order::where('number',$params['number'])->first();
            $order->return_fee+=$params['return_fee'];
            $order->refund_at =  date('Y-m-d H:i:s');
            if($order->return_fee == $order->fee){
                $order->status = Order::STATUS_REFUNDED;
            }else{
                $order->status = Order::STATUS_END;
            }
            $order->save();
            if($refund->is_normal == 1){
                $normal['fee'] = $params['return_fee'];
                $order->normalRefundSuccess($normal);
            }
        }else{
            $refund = RefundLog::where('refund_no',$params['refund_no'])
                ->first();
            $refund->status = 2;
            $refund->save();
        }
        return $data;
    }
    public function balanceRefund($params){
        $data = Pay::alipay($this->config)->refund([
            'out_trade_no' => $params['number'],
            'refund_amount' => $params['return_fee'],
            '_action' => 'mini',
            'out_request_no'=>$params['refund_no']
        ]);
        if($data['code'] == 10000){
            $refund = RefundLog::where('refund_no',$params['refund_no'])
                ->first();
            $refund->status = 1;
            $refund->refund_time= date('Y-m-d H:i:s');
            $refund->save();
            $order = BalanceOrder::where('number',$params['number'])->first();
            $order->return_fee+=$params['return_fee'];
            $order->status = Order::STATUS_REFUNDED;
//            $order->refund_at =  date('Y-m-d H:i:s');
            $order->save();

        }else{
            $refund = RefundLog::where('refund_no',$params['refund_no'])
                ->first();
            $refund->status = 2;
            $refund->save();
        }
        return $data;
    }



    /**同步关闭订单
     * @param string $order_no
     * @return void
     * @throws \Yansongda\Pay\Exception\ContainerException
     * @throws \Yansongda\Pay\Exception\InvalidParamsException
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
     */
    public function cancel(string $order_no)
    {
        $order_close = [
            'out_trade_no' => $order_no,
        ];
        return Pay::alipay($this->config)->close($order_close);
    }


    public function miniPay($params){
        $order = [
            'out_trade_no' => $params['number'],
            'total_amount' => number_format((float)$params['amount'],2,'.',''),
            'subject' => $params['description'],
            'buyer_id' => $params['openid'],
        ];
        return Pay::alipay($this->config)->mini($order)->toArray();

//        return $result->get('trade_no');  // 支付宝交易号
// return $result->trade_no;
    }


    public function miniBalance($params){
        $this->config['alipay']['default']['notify_url'] = $params['notify_url'];
        Pay::config(array_merge($this->config,['_force'=>true]));
        $order = [
            'out_trade_no' => $params['number'],
            'total_amount' => number_format((float)$params['amount'],2,'.',''),
            'subject' => $params['description'],
            'buyer_id' => $params['openid']
        ];
        return Pay::alipay()->mini($order)->toArray();
    }


}
